package com.chey.config;

import com.chey.dao.PermissionDao;
import com.chey.domain.ResponseData;
import com.chey.filter.TokenFilter;
import com.chey.util.RedisCache;
import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.http.SecurityHeaders;
import org.springframework.web.cors.CorsConfigurationSource;


import java.io.IOException;

/**
 * @author JanYao
 * @version 0.1
 */
@Configuration

public class SecurityConfig{

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private TokenFilter tokenFilter;

    @Autowired
    private UserDetailsService service;

    @Autowired
    private SecurityRuler securityRuler;

    @Autowired
    private CorsConfigurationSource corsConfigurationSource;


//    @Autowired
//    private PersistentTokenRepository tokenRepository;

        @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            http

                    .authorizeHttpRequests((aut)->aut  //对请求的认证方式的设置
                            .requestMatchers("/some","/detail","/apply").permitAll()
                            .requestMatchers(HttpMethod.GET,"/reg/**").permitAll()//对some接口的访问不需要认证
                            .anyRequest() //任何请求都需要认证
                            .access(securityRuler)
                    )
                    .formLogin((login)->login   //关于登录表单的相关配置
                            .loginProcessingUrl("/doLogin")
                            .successForwardUrl("/index")
                            .failureHandler((request, response, exception) -> {
                                response.setContentType("application/json;charset=utf-8");
                                ResponseData data = new ResponseData();
                                data.setCode(401);
                                data.setData("登陆失败");
                                response.getWriter().write(new ObjectMapper().writeValueAsString(data));
                            })

                    )
                    .oauth2Login() //开启oauth2登录
                    .and()//配置的登录接口的路径名) //登录错误的目标地址
                    .userDetailsService(service); //注入登录的业务逻辑
            http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
                @Override
                public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                    //编写异常处理代码
                    response.setCharacterEncoding("utf-8");
                    response.setContentType("text/html;charset=utf-8");
                    response.getWriter().print("帐号未授权！请联系管理员！");
                }
            });
            http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
                response.setContentType("application/json;charset=utf-8");
                ResponseData data = new ResponseData();
                data.setCode(401);
                data.setData("未登录,请先登录");
                response.getWriter().write(new ObjectMapper().writeValueAsString(data));
            });
            //session失效后跳转的地址
//            http.sessionManagement()
//            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//            .maximumSessions(1)
//            .maxSessionsPreventsLogin(true)
//            .expiredUrl("/sessionOut");

            http.logout().logoutUrl("/logout").permitAll().logoutSuccessHandler((request, response, authentication) -> {

                boolean token = redisCache.deleteObject("login:token:" + request.getHeader("Authorization"));
                SecurityContextHolder.clearContext();

                response.setContentType("application/json;charset=utf-8");
                ResponseData data = new ResponseData();
                data.setCode(200);
                data.setData("LOGOUT");
                response.getWriter().write(new ObjectMapper().writeValueAsString(data));
            });

//            http.rememberMe((me)->me
//                    //.tokenValiditySeconds(10)  //单位时秒，设置时间，默认是2周
//                    .tokenRepository(tokenRepository)
     //       );
            http.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class);
            http.cors().configurationSource(corsConfigurationSource);
            http.csrf().disable(); //csrf失效
            return http.build();

    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/error");
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration)throws Exception{
        return configuration.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        //创建BCryptPasswordEncoder注入容器 md5密码加密
        return new BCryptPasswordEncoder();
    }
}
